package com.loie.xcx.syUtil;

import com.alibaba.fastjson2.JSON;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @author yangzhiqiang
 * @since 2020-09-07
 */
public class HttpUtil {
    private static final String SIGNATURE_ALGORITHM = "SHA256WithRSA";

    private static PrivateKey myPriKey; //对接企业私钥
    private static PublicKey llsPubKey; //lls公钥
    private static final Logger paramLogger = LoggerFactory.getLogger("banklog");
    public static String postString(String sendMsg, boolean isPlaintext, String url) throws Exception {
        return commonPost(sendMsg, isPlaintext, url);
    }

    public static String postObject(String channel, Object request, boolean isPlaintext, boolean isPrd, String url, String serialNo) throws Exception {
        System.err.println("serialNo: \n" + serialNo);

        //3. 构建请求体
        Map<String, Object> param = new HashMap<>(8);
        param.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        param.put("version", "1.0.0");
        param.put("channel", channel);
        param.put("serialNo", serialNo);

        if (isPlaintext) {
            param.put("isPlaintext", true);
            param.put("data",  JSON.toJSONString(request));
        } else {
            //1. 初始化私钥公钥
            initKeys(isPrd, channel);

            //2. 生成随机对称加密密钥
            String plainKey = AESUtils.getRandomKey();
            String encryptKey = RSAUtils.encryptByPublicKey(plainKey, llsPubKey);
            param.put("key", encryptKey);
            System.err.println("plainKey: \n" + plainKey); //88451744749f6f5
            System.err.println("encryptKey: \n" + encryptKey); //VCbxc8alguo6eO/ittuq3ZbLsCouvC1abDHq7Z1qycjt3r9ufV+uLnG4AGxC3xUCI3MMpPEV65ZMmGEt9KmoL2O60vZvW2pJ7b7rMk2Pi7yFKROCRi1jHCktfZfnoXRhoQsYl0gV+G6AUDAEscCAjrVnoyJsnG2H1JmlD+O37UQ=

            //4. 加密数据
            System.err.println("request: \n" + JSON.toJSONString(request));
            String encryptData = AESUtils.encryptWithBC(JSON.toJSONString(request), plainKey);
            System.err.println("encryptData: \n" + encryptData); //VGxphLCtjZxTvRfGVY5bXjGs5JaD8kQVvNTp9YZR6oABtN8xxXGu8+YFkrxOT+buuNigl8Hu3Kb4pRo+2avZZQ==
            param.put("data", encryptData);

            //5. 签名
            String plainText = StringUtil.getOrderByLexicographic(param);
            String signedText = EncryptUtils.sign(plainText, "SHA256WithRSA", myPriKey);
            param.put("signature", signedText);
            System.err.println("signedText: \n" + signedText); //ESz/Z9VX5iYdLgfdNmjdANjmWzV9KJBbxCQ/79AAzjfISeYmo48fXIOPLOLaTIzItYfKWLIwOOxijVuL2wFXbfS3Tv6YqIKGWKK6778EmD6ZQF6kO1kxC9cFl4IKL2C/pvNUAfhHK9m6F9PUEHV9Dlq6NHbgtsVpkl5gySXln8U=
        }

        //6. 请求
        String sendMsg = JSON.toJSONString(param);
        return commonPost(sendMsg, isPlaintext, url);
    }

    //************加密加钥过程***********
    public static String encode_key(String channel, Object request, boolean isPlaintext, boolean isPrd, String url, String serialNo) throws Exception {
        System.err.println("serialNo: \n" + serialNo);

        //3. 构建请求体
        Map<String, Object> param = new HashMap<>(8);
        param.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        param.put("version", "1.0.0");
        param.put("channel", channel);
        param.put("serialNo", serialNo);

        if (isPlaintext) {
            param.put("isPlaintext", true);
            param.put("data", JSON.toJSONString(request));
        } else {
            //1. 初始化私钥公钥
            initKeys(isPrd, channel);

            //2. 生成随机对称加密密钥
            String plainKey = AESUtils.getRandomKey();
            String encryptKey = RSAUtils.encryptByPublicKey(plainKey, llsPubKey);
            param.put("key", encryptKey);
            System.err.println("plainKey: \n" + plainKey); //88451744749f6f5
            System.err.println("encryptKey: \n" + encryptKey); //VCbxc8alguo6eO/ittuq3ZbLsCouvC1abDHq7Z1qycjt3r9ufV+uLnG4AGxC3xUCI3MMpPEV65ZMmGEt9KmoL2O60vZvW2pJ7b7rMk2Pi7yFKROCRi1jHCktfZfnoXRhoQsYl0gV+G6AUDAEscCAjrVnoyJsnG2H1JmlD+O37UQ=

            //4. 加密数据
            System.err.println("request: \n" + JSON.toJSONString(request));
            String encryptData = AESUtils.encryptWithBC(JSON.toJSONString(request), plainKey);
            //System.err.println("encryptData: \n" + encryptData); //VGxphLCtjZxTvRfGVY5bXjGs5JaD8kQVvNTp9YZR6oABtN8xxXGu8+YFkrxOT+buuNigl8Hu3Kb4pRo+2avZZQ==
            param.put("data", encryptData);

            //5. 签名
            String plainText = StringUtil.getOrderByLexicographic(param);
            String signedText = EncryptUtils.sign(plainText, "SHA256WithRSA", myPriKey);
            param.put("signature", signedText);
            //System.err.println("signedText: \n" + signedText); //ESz/Z9VX5iYdLgfdNmjdANjmWzV9KJBbxCQ/79AAzjfISeYmo48fXIOPLOLaTIzItYfKWLIwOOxijVuL2wFXbfS3Tv6YqIKGWKK6778EmD6ZQF6kO1kxC9cFl4IKL2C/pvNUAfhHK9m6F9PUEHV9Dlq6NHbgtsVpkl5gySXln8U=
        }

        //6. 请求
        String sendMsg = JSON.toJSONString(param);
        return  sendMsg;
    }



    private static String commonPost(String sendMsg, boolean isPlaintext, String url) throws Exception {
        System.err.println("sendMsg: \n" + sendMsg); //{"channel":"bosc","data":"VGxphLCtjZxTvRfGVY5bXjGs5JaD8kQVvNTp9YZR6oABtN8xxXGu8+YFkrxOT+buuNigl8Hu3Kb4pRo+2avZZQ==","version":"1.0.0","signature":"ESz/Z9VX5iYdLgfdNmjdANjmWzV9KJBbxCQ/79AAzjfISeYmo48fXIOPLOLaTIzItYfKWLIwOOxijVuL2wFXbfS3Tv6YqIKGWKK6778EmD6ZQF6kO1kxC9cFl4IKL2C/pvNUAfhHK9m6F9PUEHV9Dlq6NHbgtsVpkl5gySXln8U=","key":"VCbxc8alguo6eO/ittuq3ZbLsCouvC1abDHq7Z1qycjt3r9ufV+uLnG4AGxC3xUCI3MMpPEV65ZMmGEt9KmoL2O60vZvW2pJ7b7rMk2Pi7yFKROCRi1jHCktfZfnoXRhoQsYl0gV+G6AUDAEscCAjrVnoyJsnG2H1JmlD+O37UQ=","timestamp":"20201020211839"}
        Map<String, Object> resultMap = HttpUtil.doPost(sendMsg, url);
        String respStr = JSON.toJSONString(resultMap);
        paramLogger.info("接收加密数据: \n" + respStr); //{"data":"v+RpE5AIr4t55yxna/Y+sHSuMj46nZyQoGcnco5rmlfqomLOkKCz8RgLYmfRRMcidHhFII6nsP9nCSlTNf3YZQ==","signature":"CV2DGXfKTY7KgDR7K6YaVGXyxTpdkADXj5HKLQsoDaH9dI/vuGsS3AWV0x19uNp5abOOYHQKMOtKhnf1uKwaAQW9Nskws/tgQpBypNGSXAMSLzW7fPXF35Mdxy8Zsc4COH4jE7aLHg3z9vkHxXVHvacC8qGaqcYk9STxa9nCc3s=","version":"1.0.0","key":"VlUeyupWeQW6v2nMdLoxhT7w8YGH1dg93UuCoZTHZRsx65q8Z5VDSi+9RjeqVZW3IdZyK3Yh8yZp6AorGJEQtt56YN+cRZUGS8+nYWWKkXcx6C6izCAzHV+R8astkh24tI4f1DYlBz+o65Dsp15q2fwLFLKQIx4owuwVDxZ8V1A=","timestamp":"20201020211839"}

        if (isPlaintext) {
            return respStr;
        } else {
            //7. 验签
            String signature = (String) resultMap.remove("signature");
            System.err.println("signature: \n" + signature); //CV2DGXfKTY7KgDR7K6YaVGXyxTpdkADXj5HKLQsoDaH9dI/vuGsS3AWV0x19uNp5abOOYHQKMOtKhnf1uKwaAQW9Nskws/tgQpBypNGSXAMSLzW7fPXF35Mdxy8Zsc4COH4jE7aLHg3z9vkHxXVHvacC8qGaqcYk9STxa9nCc3s=
            String orderedText = StringUtil.getOrderByLexicographic(resultMap);
            System.err.println("orderedText: \n" + orderedText); //798BE51B286A0A4790BAC06217D9750170AF944F353BF3BD0014D59B0B9F7444
            boolean pass = StringUtil.verify(orderedText, signature, SIGNATURE_ALGORITHM, llsPubKey);
            if (!pass) {
                System.err.println("验签失败");
                return null;
            }

            //8.1 解密密钥
            byte[] decryptKey = RSAUtils.decryptByPrivateKey(Base64.getDecoder().decode(resultMap.get("key").toString()),
                    org.apache.commons.codec.binary.Base64.encodeBase64String(myPriKey.getEncoded()), "RSA");
            String decryptKeyStr = new String(decryptKey);
            System.err.println("decryptKeyStr: \n" + decryptKeyStr); //4b09b4e6936fc95c

            //8.2 解密数据
            String data = AESUtils.decryptWithBC(resultMap.get("data") + "", decryptKeyStr);
            System.err.println("data: \n" + data); //{"msg":"执行成功","code":200,"data":{"companyName":"bosc","socialCode":5940324803282345}}
            return data;
        }
    }




    public static String decode_key(String channel, String receiveMsg, boolean isPlaintext, String url) throws Exception {
        //System.err.println("sendMsg: \n" + sendMsg); //{"channel":"bosc","data":"VGxphLCtjZxTvRfGVY5bXjGs5JaD8kQVvNTp9YZR6oABtN8xxXGu8+YFkrxOT+buuNigl8Hu3Kb4pRo+2avZZQ==","version":"1.0.0","signature":"ESz/Z9VX5iYdLgfdNmjdANjmWzV9KJBbxCQ/79AAzjfISeYmo48fXIOPLOLaTIzItYfKWLIwOOxijVuL2wFXbfS3Tv6YqIKGWKK6778EmD6ZQF6kO1kxC9cFl4IKL2C/pvNUAfhHK9m6F9PUEHV9Dlq6NHbgtsVpkl5gySXln8U=","key":"VCbxc8alguo6eO/ittuq3ZbLsCouvC1abDHq7Z1qycjt3r9ufV+uLnG4AGxC3xUCI3MMpPEV65ZMmGEt9KmoL2O60vZvW2pJ7b7rMk2Pi7yFKROCRi1jHCktfZfnoXRhoQsYl0gV+G6AUDAEscCAjrVnoyJsnG2H1JmlD+O37UQ=","timestamp":"20201020211839"}

        Map<String, Object> resultMap = new HashMap<>();
         resultMap =(Map<String, Object>) JSON.parseObject(receiveMsg);

        String respStr = JSON.toJSONString(resultMap);
        System.err.println("resultMap: \n" + respStr); //{"data":"v+RpE5AIr4t55yxna/Y+sHSuMj46nZyQoGcnco5rmlfqomLOkKCz8RgLYmfRRMcidHhFII6nsP9nCSlTNf3YZQ==","signature":"CV2DGXfKTY7KgDR7K6YaVGXyxTpdkADXj5HKLQsoDaH9dI/vuGsS3AWV0x19uNp5abOOYHQKMOtKhnf1uKwaAQW9Nskws/tgQpBypNGSXAMSLzW7fPXF35Mdxy8Zsc4COH4jE7aLHg3z9vkHxXVHvacC8qGaqcYk9STxa9nCc3s=","version":"1.0.0","key":"VlUeyupWeQW6v2nMdLoxhT7w8YGH1dg93UuCoZTHZRsx65q8Z5VDSi+9RjeqVZW3IdZyK3Yh8yZp6AorGJEQtt56YN+cRZUGS8+nYWWKkXcx6C6izCAzHV+R8astkh24tI4f1DYlBz+o65Dsp15q2fwLFLKQIx4owuwVDxZ8V1A=","timestamp":"20201020211839"}

        if (isPlaintext) {
            return respStr;
        } else {
            //7. 验签
            initKeys(false, channel);
            String signature = (String) resultMap.remove("signature");
            //System.out.println("signature: \n" + signature);
            System.err.println("signature: \n" + signature); //CV2DGXfKTY7KgDR7K6YaVGXyxTpdkADXj5HKLQsoDaH9dI/vuGsS3AWV0x19uNp5abOOYHQKMOtKhnf1uKwaAQW9Nskws/tgQpBypNGSXAMSLzW7fPXF35Mdxy8Zsc4COH4jE7aLHg3z9vkHxXVHvacC8qGaqcYk9STxa9nCc3s=
            String orderedText = StringUtil.getOrderByLexicographic(resultMap);
            System.err.println("orderedText: \n" + orderedText); //798BE51B286A0A4790BAC06217D9750170AF944F353BF3BD0014D59B0B9F7444
            boolean pass = StringUtil.verify(orderedText, signature, SIGNATURE_ALGORITHM, llsPubKey);
            if (!pass) {
                System.err.println("验签失败");
                return null;
            }

            //8.1 解密密钥
            byte[] decryptKey = RSAUtils.decryptByPrivateKey(Base64.getDecoder().decode(resultMap.get("key").toString()),
                    org.apache.commons.codec.binary.Base64.encodeBase64String(myPriKey.getEncoded()), "RSA");
            String decryptKeyStr = new String(decryptKey);
            System.err.println("decryptKeyStr: \n" + decryptKeyStr); //4b09b4e6936fc95c

            //8.2 解密数据
            String data = AESUtils.decryptWithBC(resultMap.get("data") + "", decryptKeyStr);
            System.err.println("data: \n" + data); //{"msg":"执行成功","code":200,"data":{"companyName":"bosc","socialCode":5940324803282345}}
            return data;
        }
    }


    public static Map<String, Object> doPost(String msg, String url) throws IOException {
        CloseableHttpResponse response = null;
        Map<String, Object> resultMap = null;
        try {
            CloseableHttpClient httpclient = HttpClients.createDefault();

            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(new StringEntity(msg, StandardCharsets.UTF_8));
            httpPost.setHeader("Content-Type", "application/json;charset=utf8");
            httpPost.setHeader("Std-Channel-Prefix", "bosc");

//            log.info("请求地址:{}", url);
//            log.info("请求内容:{}", msg);
            response = httpclient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            InputStream in = entity.getContent();
            String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            //resultMap = new HashMap<>(JSONUtils.parseObject(result, Map.class));
            resultMap =(Map<String, Object>) JSON.parseObject(result);
            System.err.println("请求返回状态: \n" + response.getStatusLine());
            System.err.println("请求返回数据: \n" + result);

            in.close();
        } catch (Exception e) {
//            log.info("请求wec出错", e);
            throw e;
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
//                    log.info("关闭流出错", e);
                }
            }
        }
        return resultMap;
    }

    private static void initKeys(boolean isPrd, String channel) throws Exception {
        String dest="";
        if (isPrd) {
            //1. 初始化私钥
//            myPriKey = EncryptUtils.getPrivateKey(dir + "certs-prd/" + channel + "-pri.pfx", "你的私钥密码", "PKCS12");
            myPriKey = EncryptUtils.getPrivateKey(dest+"certs-prd/" + channel + "-pri.pfx", "111111", "PKCS12");

            //2. 初始化公钥
            llsPubKey = EncryptUtils.getPublicKey(dest+"certs-prd/lls-pub.pem");
           // llsPubKey = EncryptUtils.getPublicKey("/certs-prd/bosc-pub.pem");
        } else {
            //1. 初始化私钥
            myPriKey = EncryptUtils.getPrivateKey(dest+"/certs/" + channel + "-pri.pfx", "111111", "PKCS12");
            //2. 初始化公钥
            llsPubKey = EncryptUtils.getPublicKey(dest+"certs/lls-pub.pem");
            //llsPubKey = EncryptUtils.getPublicKey("/certs-prd/bosc-pub.pem");
        }
    }

}
